package him.works.trainapp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.res.AssetManager;
import android.util.Log;

public class Utils {

	public static final String NAME_RESULT_SET = "result";
	public static final String DATA_URL = "http://pipes.yahoo.com/pipes/pipe.run?";
	public static final String AMPERSAND = "&";
	public static final String COLON = ":";
	public static final String EMPTY = "";
	public static final String CONST_P = "p";
	public static final String CONST_STN = "station";
	public static final String CONST_CONTENT = "content";
	public static final String PIPE_APP_ID = "_id=b23ea51d8b9439becf57878adf3b4335";
	public static final String RESPONSE_FORMAT_JSON = "_render=json";
	public static final String FILE_UTILS = "utils.properties";
	public static final String FILE_LINES = "lines.properties";
	
	public static int WORK_PROGRESS = 0;
	
	private static final HashMap<String, String> MAP_UTILS = new HashMap<String, String>();
	
	private static JSONObject jsonResp;

	public static ArgumentsBean getArgumentBean(Context context,
			String strFromStn, String strDirection, String strLine,
			int iPickedHour, int iPickedMinute) {

		strDirection = getValueOfKey(context, FILE_UTILS, MAP_UTILS, strDirection);
		String strDirnQuery = (strDirection==null || strDirection.isEmpty()) ? (strDirection)
				: ("Direction=" + strDirection);
		String strLineQuery = (strLine==null || strLine.isEmpty()) ? (strLine)
				: ("Line=" + strLine);
		String strFromStnQuery = (strFromStn==null || strFromStn.isEmpty()) ? (strFromStn)
				: ("Station=" + strFromStn);
		String strRequestUrl = DATA_URL + strDirnQuery + AMPERSAND
				+ strLineQuery + AMPERSAND + strFromStnQuery + AMPERSAND
				+ PIPE_APP_ID + AMPERSAND + RESPONSE_FORMAT_JSON;
		Log.i("BANANA", "strRequestUrl: " + strRequestUrl);
		ArgumentsBean argbeanObj = new ArgumentsBean();
		argbeanObj.setStrRequestUrl(strRequestUrl);
		argbeanObj.setIPickedHour(iPickedHour);
		argbeanObj.setIPickedMinute(iPickedMinute);
		return argbeanObj;
	}

	public static String getResultFromUrl(ArgumentsBean argbeanObj) {

		BufferedReader bufreader = null;
		StringBuilder strbuildResponse = new StringBuilder();
		try {
			Log.i("BANANA",
					"making url connection using: "
							+ argbeanObj.getStrRequestUrl());
			URL urlRequest = new URL(argbeanObj.getStrRequestUrl());
			URLConnection urlconn = urlRequest.openConnection();
			Log.i("BANANA", urlconn.getURL().toString());
			bufreader = new BufferedReader(new InputStreamReader(
					urlRequest.openStream()));
			String strResponseLine = null;
			while ((strResponseLine = bufreader.readLine()) != null) {
				strbuildResponse.append(strResponseLine);
			}
		} catch (IOException e) {
			e.printStackTrace();
			return Utils.EMPTY;
		} finally {
			try {
				if (bufreader != null) {
					bufreader.close();
				}
			} catch (IOException ex) {
				Log.i("BANANA", "Entered exception: " + ex.getMessage());
				ex.printStackTrace();
			}
		}
		return strbuildResponse.toString();
	}

	public static ArrayList<String> getTrainStations(ArgumentsBean argbeanObj) {
		ArrayList<String> listResult = new ArrayList<String>();
		try {
			String strResponseJson = getResultFromUrl(argbeanObj);
			jsonResp = new JSONObject(strResponseJson);
			Log.i("BANANA", "Response JSON: " + strResponseJson);
			JSONArray jsarrayTiming = jsonResp.getJSONObject("value")
					.getJSONArray("items");
			int iArraySize = jsarrayTiming.length();
			JSONObject jsonTmp = null;
			String strTmp = null;
			for (int i = 0; i < iArraySize; ++i) {
				jsonTmp = jsarrayTiming.getJSONObject(i);
				try {
					strTmp = jsonTmp.getString(CONST_STN);
					listResult.add(strTmp);
					WORK_PROGRESS = (i / iArraySize) * 100;
				} catch (JSONException exJsonExtract) {
					Log.e("BANANA", "Exception in station extraction ... : "
							+ jsarrayTiming);
				}
			}
			Log.i(Utils.class.getCanonicalName(),
					"Stations: \n\n" + listResult.get(0));
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return listResult;
	}

	public static ArrayList<String> getTrainTimes(ArgumentsBean argbeanObj) {

		ArrayList<String> listResult = new ArrayList<String>();

		try {
//			JSONObject jsonResp = new JSONObject(getResultFromUrl(argbeanObj));
			JSONArray jsarrayTiming = jsonResp.getJSONObject("value")
					.getJSONArray("items").getJSONObject(0)
					.getJSONArray("timing");
			// String strTimings =
			// jsonResp.getJSONObject("value").getJSONArray("items").getJSONObject(0).getJSONArray("timings");
			// String []strArTimings = strTimings.split(",");
			ArrayList<String> listValuesUnorg = new ArrayList<String>();
			int iArraySize = jsarrayTiming.length();
			JSONObject jsonTmp = null;
			String strTmp = null;
			Pattern patnTime = Pattern.compile("\\d{2}:\\d{2}");
			Matcher matchTime = null;
			for (int i = 0; i < iArraySize; ++i) {
				jsonTmp = jsarrayTiming.getJSONObject(i);
				try {
					strTmp = jsonTmp.getString(CONST_P);
				} catch (JSONException exJsonExtract) {
					strTmp = jsonTmp.getJSONObject(CONST_P).getString(
							CONST_CONTENT);
				}
				matchTime = patnTime.matcher(strTmp);
				if (matchTime.matches()) {
					// Log.i("BANANA", "if(matchTime.matches()) MATCHED");
					listValuesUnorg.add(strTmp);
				}
			}
			listResult = convertToOrgList(listValuesUnorg,
					argbeanObj.getIPickedHour(), argbeanObj.getIPickedMinute());
			// Log.i(Utils.class.getCanonicalName(), "Timings: \n\n" +
			// strTimings);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		return listResult;
	}

	public static ArrayList<String> convertToOrgList(
			ArrayList<String> listValuesUnorg, int iPickedHour,
			int iPickedMinute) {
		ArrayList<String> listValues = new ArrayList<String>();
		String strHour = null;
		String strMinute = null;
		String[] strTmpSplit = null;
		int iListCounter = 0;
		int iListSize = listValuesUnorg.size();
		for (int i = 0; (i < iListSize) && (iListCounter < 3); i++) {
			String strTmp = listValuesUnorg.get(i);
			if (null != strTmp) {
				if (strTmp.trim().isEmpty()) {
					Log.i("BANANA", "strTmp is EMPTY");
					continue;
				}
				try {
					Log.i("BANANA", "strTmp: " + strTmp);
					strTmpSplit = strTmp.split(COLON);
					Log.i("BANANA", "strTmp: has been split");
					strHour = strTmpSplit[0].trim();
					strMinute = strTmpSplit[1].trim();
					Log.i("BANANA", "strHour: " + strHour + " | strMinute: "
							+ strMinute);
					int iHour = Integer.parseInt(strHour);
					Log.i("BANANA", "iHour: " + iHour);
					if (iHour < iPickedHour) {
						continue;
					}
					int iMinute = 0;
					try {
						iMinute = Integer.parseInt(strMinute);
						Log.i("BANANA", "iMinute: " + iMinute);
					} catch (NumberFormatException exNf) {
						Log.i("BANANA", "EXCEPTION iMinute: " + iMinute);
						continue;
					}

					if (iHour == iPickedHour) {
						if (iMinute < iPickedMinute) {
							continue;
						}
					}
				} catch (Exception ex) {
					Log.e("BANANA", "Exception encountered: " + ex.getMessage()
							+ " | strTmp: " + strTmp);
					continue;
				}
				listValues.add(strHour + COLON + strMinute);
				++iListCounter;
			}
		}
		return listValues;
	}

	public static class ArgumentsBean {
		private int iPickedHour;
		private int iPickedMinute;
		private String strRequestUrl;

		public String getStrRequestUrl() {
			return strRequestUrl;
		}

		public int getIPickedHour() {
			return iPickedHour;
		}

		public int getIPickedMinute() {
			return iPickedMinute;
		}

		public void setStrRequestUrl(String strRequestUrl) {
			this.strRequestUrl = strRequestUrl;
		}

		public void setIPickedHour(int iPickedHour) {
			this.iPickedHour = iPickedHour;
		}

		public void setIPickedMinute(int iPickedMinute) {
			this.iPickedMinute = iPickedMinute;
		}
	}
	
	/**
	 * Creates a map from a properties file
	 * @param context android application context
	 * @param strFile properties file to be read
	 * @return resulting map object
	 */
	public static Map<String, String> getMapFromProperties(Context context, String strFile) {
		Map<String, String> mapObj = new HashMap<String, String>();
		Properties prop = new Properties();
		InputStream input = null;
		try {
			AssetManager astmgr = context.getAssets();
			input = astmgr.open(strFile);
			prop.load(input);
			for (String strTmp : prop.stringPropertyNames()) {
				mapObj.put(strTmp, prop.getProperty(strTmp));
			}
		} catch (IOException ex) {
			input = null;
			Log.e("BANANA", "EXCEPTION", ex);
		} finally {
			try {
				if (input != null) {
					input.close();
					input = null;
				}
			} catch (IOException ex) {
				input = null;
				Log.e("BANANA", "EXCEPTION", ex);
				return null;
			}
		}		
		return mapObj;
	}
	
	/**
	 * Creates a String Array of keys in a map
	 * @param mapObj Map object whose keys need to returned as a String Array
	 * @return
	 */
	public static String[] getArrayOfMapValues(Map<String, String> mapObj) {
		String [] strarrKeys = null;
		Set<String> setKeys = mapObj.keySet();
		strarrKeys = new String[setKeys.size()];
		int iCounter = 0;
		for(String strTmp : setKeys) {
			strarrKeys[iCounter++] = mapObj.get(strTmp);
		}		
		return strarrKeys;
	}

	/**
	 * Gives the value of a key in a map 
	 * @param context android application context
	 * @param strFile properties file name
	 * @param mapObj map to be read
	 * @param strKey key whose value needs to be searched
	 * @return value of the key 'strKey' in the map 'mapUtils'
	 */
	public static String getValueOfKey(Context context, String strFile,
			Map<String, String> mapObj, String strKey) {
		String strValue = null;

		Log.i("BANANA", "getValueOfKey(String strKey)");
		if (mapObj.isEmpty()) {
			Log.i("BANANA", "mapUtils.isEmpty()");
			mapObj = getMapFromProperties(context, strFile);
		}
		if (mapObj.containsKey(strKey)) {
			Log.i("BANANA", "mapUtils.containsKey(strKey)");
			strValue = mapObj.get(strKey);
		}
		return strValue;
	}
	
	public static String getKeyOfMapValues(Context context, String strFile,
			Map<String, String> mapObj, String strValue) {
		String strKey = null;

		Log.i("BANANA", "getValueOfKey(String strKey)");
		if (mapObj.isEmpty()) {
			Log.i("BANANA", "mapUtils.isEmpty()");
			mapObj = getMapFromProperties(context, strFile);
		}
		Set<String> setKeys = mapObj.keySet();
		for(String strTmp : setKeys) {
			if(strValue.equals(mapObj.get(strTmp))) {
				strKey = strTmp;
			}
		}
		return strKey;
	}
}
